package crypto.prng;

/**
 * A thread based seed generator - one source of randomness.
 * <p>
 * Based on an idea from Marcus Lippert.
 * </p>
 */
public class ThreadedSeedGenerator {
	private class SeedGenerator implements Runnable {
		private volatile int counter = 0;
		private volatile boolean stop = false;

		public void run() {
			while (!this.stop) {
				this.counter++;
			}

		}

		public byte[] generateSeed(int numbytes, boolean fast) {
			Thread t = new Thread(this);
			byte[] result = new byte[numbytes];
			this.counter = 0;
			this.stop = false;
			int last = 0;
			int end;

			t.start();
			if (fast) {
				end = numbytes;
			} else {
				end = numbytes * 8;
			}
			for (int i = 0; i < end; i++) {
				while (this.counter == last) {
					try {
						Thread.sleep(1);
					} catch (InterruptedException e) {
						// ignore
					}
				}
				last = this.counter;
				if (fast) {
					result[i] = (byte) (last & 0xff);
				} else {
					int bytepos = i / 8;
					result[bytepos] = (byte) ((result[bytepos] << 1) | (last & 1));
				}

			}
			stop = true;
			return result;
		}
	}

	/**
	 * Generate seed bytes. Set fast to false for best quality.
	 * <p>
	 * If fast is set to true, the code should be round about 8 times faster
	 * when generating a long sequence of random bytes. 20 bytes of random
	 * values using the fast mode take less than half a second on a Nokia e70.
	 * If fast is set to false, it takes round about 2500 ms.
	 * </p>
	 * 
	 * @param numBytes
	 *            the number of bytes to generate
	 * @param fast
	 *            true if fast mode should be used
	 */
	public byte[] generateSeed(int numBytes, boolean fast) {
		SeedGenerator gen = new SeedGenerator();

		return gen.generateSeed(numBytes, fast);
	}
}
